home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Files / XTND 1.3.6 / Application Examples / PascalSource / THINK ƒ / XTEStyleSample.p < prev    next >
Encoding:
Text File  |  1992-01-16  |  50.8 KB  |  1,623 lines  |  [TEXT/PJMM]

  1. {------------------------------------------------------------------------------}
  2. {#}
  3. {#    Apple Macintosh Developer Technical Support}
  4. {#}
  5. {#    XTND-Capable, MultiFinder-Aware Simple Styled TextEdit Sample Application}
  6. {#}
  7. {#    XTEStyleSample}
  8. {#}
  9. {#    XTEStyleSample.p    -    Pascal Source}
  10. {#}
  11. {#    Copyright © 1989 Apple Computer, Inc.}
  12. {#    All rights reserved.}
  13. {#}
  14. {#    Versions:    1.0                        10/89}
  15. {#                2.0                        3/91}
  16. {#}
  17. {#    Components:    XTEStyleSample.p            March 29, 1991}
  18. {#                XTEStyleSampleGlue.a        March 29, 1991}
  19. {#                XTEStyleSample.r            March 29, 1991}
  20. {#                XTEStyleSample.h            March 29, 1991}
  21. {#                XTEStyleSample.make            March 29, 1991}
  22. {#}
  23. {#    XTEStyleSample is an example application that demonstrates how }
  24. {#    to initialize the commonly used toolbox managers, operate }
  25. {#    successfully under MultiFinder, handle desk accessories and }
  26. {#    create, grow, and zoom windows. Both styled and fundamental TextEdit }
  27. {#    toolbox calls and TextEdit autoscroll are demonstrated. It }
  28. {#    also shows how to create and maintain scrollbar controls as well}
  29. {#    as implementing a basic printing loop. In addition, it has the}
  30. {#    capability to import or export via XTND technology. Thus you can }
  31. {#    save to MacWrite, MS Word, etc. or Open WordPerfect, or other files}
  32. {#    for which you have translators available.}
  33. {#}
  34. {#    It does not by any means demonstrate all the techniques you }
  35. {#    need for a large application. In particular, XTEStyleSample does not }
  36. {#    cover exception handling, multiple windows/documents, }
  37. {#    sophisticated memory management, or undo. All of }
  38. {#    these are vital parts of a normal full-sized application.}
  39. {#}
  40. {#    This application is an example of the form of a Macintosh }
  41. {#    application; it is NOT a template. It is NOT intended to be }
  42. {#    used as a foundation for the next world-class, best-selling, }
  43. {#    600K application. A stick figure drawing of the human body may }
  44. {#    be a good example of the form for a painting, but that does not }
  45. {#    mean it should be used as the basis for the next Mona Lisa.}
  46. {#}
  47. {#    We recommend that you review this program, TEStyleSample, TESample or Sample before }
  48. {#    beginning a new application. XTEStyleSample is built from TEStyleSample, but}
  49. {#    has the added capability of importing and exporting through the XTND}
  50. {#    architecture. TESample is a simpler version of TEStyleSample}
  51. {#    without styles and Sample is a simple app. which doesn’t }
  52. {#    use TextEdit or the Control Manager.}
  53. {#}
  54. {------------------------------------------------------------------------------}
  55.  
  56.  
  57. PROGRAM XTEStyleSample;
  58.  
  59. {Segmentation strategy:}
  60. {}
  61. { This program consists of three segments. Main contains most of the code,}
  62. { including the MPW libraries, and the main program. Initialize contains}
  63. { code that is only used once, during startup, and can be unloaded after the}
  64. { program starts. %A5Init is automatically created by the Linker to initialize}
  65. { globals for the MPW libraries and is unloaded right away.}
  66.  
  67.  
  68. {SetPort strategy:}
  69. {}
  70. { Toolbox routines do not change the current port. In spite of this, in this}
  71. { program we use a strategy of calling SetPort whenever we want to draw or}
  72. { make calls which depend on the current port. This makes us less vulnerable}
  73. { to bugs in other software which might alter the current port (such as the}
  74. { bug (feature?) in many desk accessories which change the port on OpenDeskAcc).}
  75. { Hopefully, this also makes the routines from this program more self-contained,}
  76. { since they don't depend on the current port setting.}
  77.  
  78.  
  79. {Clipboard strategy: }
  80. {}
  81. { Under styled TextEdit, TECut and TECopy will write both the text and associated}
  82. { style information directly to the desk scrap as types 'TEXT' and 'styl'.}
  83. { Instead of using TEToScrap and TEFromScrap, a new routine TEStylPaste, will }
  84. { transfer the text and style from the desk scrap to the document. }
  85.  
  86. {$D+}
  87.  
  88.     USES
  89.         QuickDraw, Folders, Dialogs, Printing, traps, XTNDInterface, XTNDTextTranslator, XTNDPICTTranslator, XTEFileIO;
  90.  
  91.     CONST
  92.  
  93.     {kMaxOpenDocuments is used to determine whether a new document can be opened}
  94. {     or created. We keep track of the number of open documents, and disable the}
  95. {     menu items that create a new document when the maximum is reached. If the}
  96. {     number of documents falls below the maximum, the items are enabled again.}
  97.         kMaxOpenDocuments = 10;
  98.  
  99.     {kMinDocDim is used to limit the minimum dimension of a window when GrowWindow}
  100. {    is called.}
  101.         kMinDocDim = 64;
  102.  
  103.     {kControlInvisible is used to 'turn off' controls (i.e., cause the control not}
  104. {    to be redrawn as a result of some Control Manager call such as SetCtlValue)}
  105. {    by being put into the contrlVis field of the record. kControlVisible is used}
  106. {    the same way to 'turn on' the control.}
  107.         kControlInvisible = 0;
  108.         kControlVisible = $FF;
  109.  
  110.     {kMaxTELength is an arbitrary number used to limit the length of text in the TERec}
  111. {    so that various errors won't occur from too many characters in the text.}
  112.         kMaxTELength = 32000;
  113.     (* what about that tech note I wrote? is this a valid check anymore? maw *)
  114.  
  115.     {kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the}
  116. {     SysEnvRec we understand.}
  117.         kSysEnvironsVersion = 1;
  118.  
  119.     {kOSEvent is the event number of the suspend/resume and mouse-moved events sent}
  120. {     by MultiFinder. Once we determine that an event is an osEvent, we look at the}
  121. {     high byte of the message sent to determine which kind it is. To differentiate}
  122. {     suspend and resume events we check the resumeMask bit.}
  123.         kOSEvent = app4Evt;    { event used by MultiFinder }
  124.         kSuspendResumeMessage = 1;        { high byte of suspend/resume event message }
  125.         kResumeMask = 1;        { bit of message field for resume vs. suspend }
  126.         kMouseMovedMessage = $FA;        { high byte of mouse-moved event message }
  127.         kNoEvents = 0;        {no events mask}
  128.  
  129.     {kMinHeap - This is the minimum result from the following}
  130. {     equation:}
  131. {            }
  132. {            ORD(GetApplLimit) - ORD(ApplicZone)}
  133. {            }
  134. {     for the application to run. It will insure that enough memory will}
  135. {     be around for reasonable-sized scraps, FKEYs, etc. to exist with the}
  136. {     application, and still give the application some 'breathing room'.}
  137. {     To derive this number, we ran under a MultiFinder partition that was}
  138. {     our requested minimum size, as given in the 'SIZE' resource.}
  139.  
  140.         kMinHeap = 29 * 1024;
  141.  
  142.     {kMinSpace - This is the minimum result from PurgeSpace, when called}
  143. {     at initialization time, for the application to run. This number acts}
  144. {     as a double-check to insure that there really is enough memory for the}
  145. {     application to run, including what has been taken up already by}
  146. {     pre-loaded resources, the scrap, code, and other sundry memory blocks.}
  147.  
  148.         kMinSpace = 20 * 1024;
  149.  
  150.     {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
  151.         kExtremeNeg = -32768;
  152.         kExtremePos = 32767 - 1;    { required for old region bug }
  153.  
  154.     {kTESlop provides some extra security when pre-flighting edit commands.}
  155.         kTESlop = 1024;
  156.  
  157.     { The following constants are all menu and item IDs corresponding to their resources }
  158.  
  159.         mApple = 128;                { Apple menu }
  160.         iAbout = 1;
  161.  
  162.         mFile = 129;                { File menu }
  163.         iNew = 1;
  164.         iOpen = 2;                { Added for XTEStyleSample }
  165.         iClose = 4;
  166.         iSave = 5;                { Added for XTEStyleSample }
  167.         iSaveAs = 6;                { Added for XTEStyleSample }
  168.         iPageSetup = 9;                { Added for TEStyleSample }
  169.         iPrint = 10;                { Added for TEStyleSample }
  170.         iQuit = 12;
  171.  
  172.         mEdit = 130;                { Edit menu }
  173.         iUndo = 1;
  174.         iCut = 3;
  175.         iCopy = 4;
  176.         iPaste = 5;
  177.         iClear = 6;
  178.         iSelectAll = 8;                { Added for XTEStyleSample }
  179.  
  180.         mFont = 131;                { Font menu-added for XTEStyleSample }
  181.  
  182.         mFontSize = 132;                { Font size menu-added for XTEStyleSample }
  183.         iNine = 1;
  184.         iTen = 2;
  185.         iTwelve = 3;
  186.         iFourteen = 4;
  187.         iEighteen = 5;
  188.         iTwoFour = 6;
  189.         iOther = 7;
  190.  
  191.         mStyle = 133;                { Style menu-added for XTEStyleSample }
  192.         iPlain = 1;
  193.         iBold = 3;
  194.         iItalic = 4;
  195.         iUnderline = 5;
  196.         iOutline = 6;
  197.         iShadow = 7;
  198.  
  199.     {kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  200.         kDITop = $0050;
  201.         kDILeft = $0070;
  202.  
  203.         kStyleResType = 'styl';
  204.  
  205.         kNewWindowOffset = 20;
  206.         kWndPosResID = 6;
  207.  
  208.         kTransVersion = 2;        { this is the translator version we want }
  209.  
  210.     TYPE
  211.         WindowPosHandle = ^WindowPosPtr;
  212.         WindowPosPtr = ^WindowPosRec;
  213.         WindowPosRec = RECORD
  214.                 wndPos: Point;
  215.                 wndSize: Point;
  216.                 selStart, selEnd, scrollVal, scrollMax: INTEGER;
  217.             END;
  218.  
  219.     VAR
  220.     {The "g" prefix is used to emphasize that a variable is global.}
  221.         gMac: SysEnvRec;    { set up by Initialize }
  222.         gHasWaitNextEvent: BOOLEAN;        { set up by Initialize }
  223.         gInBackground: BOOLEAN;        { maintained by Initialize and DoEvent }
  224.         gFirstMyDlgCall: BOOLEAN;        { maintained by Initialize, DoNew, DoOpen, and DoCloseWindow }
  225.  
  226.     {New globals to support printing and style selection }
  227.         gTxStyle: TextStyle;    { holds style selected, plain default, maintained by DoMenuCommand }
  228.         gFontName: Str255;        { name of font selected, app font default, maintained by DoMenuCommand }
  229.         gFontID: INTEGER;        { ID of font selected, app font default, maintained by DoMenuCommand }
  230.         gFontSize: LONGINT;        { font size selected, 12 pt default, maintained by DoMenuCommand }
  231.         gPrinterRecord: THPrint;        { print handle, maintained by printText }
  232.         gPrinterPort: TPPrPort;        { pointer to Print Manager's GrafPort }
  233.  
  234.  
  235.     (*----- windows --------------*)
  236.         gGrayRgn: RgnHandle;
  237.         gDragRect: Rect;            (*bounds rect for dragging window*)
  238.         gSizeRect: Rect;            (*limits for resizing window*)
  239.         gInitWndPos: Point;        (*initial window pos for saved files*)
  240.         gInitScrollVal: INTEGER;
  241.         gInitScrollMax: INTEGER;
  242.         gTotalWindows: longInt;        (* Amount to offset new windows by *)
  243.  
  244.  
  245.     (*------- import ----------*)
  246.         gSaveSelected: INTEGER;
  247.         gxtErr, gError: OSErr;
  248.         gTransVersion: INTEGER;
  249.         gTransList: TransDescrHandle;
  250.  
  251.     { Get/Put Import/Export File Routine Declarations }
  252. { PROCEDURE CallFilter(pAddress: ProcPtr; pParams: Ptr); }
  253.  
  254. {$S Initialize}
  255.     FUNCTION TrapAvailable (tNumber: INTEGER; tType: TrapType): BOOLEAN;
  256.  
  257. {Check to see if a given trap is implemented. This is only used by the}
  258. { Initialize routine in this program, so we put it in the Initialize segment.}
  259. { The recommended approach to see if a trap is implemented is to see if}
  260. { the address of the trap routine is the same as the address of the}
  261. { Unimplemented trap.}
  262. {Needs to be called after call to SysEnvirons so that it can check}
  263. { if a ToolTrap is out of range of a pre-MacII ROM.}
  264. {$IFC UNDEFINED MPW}
  265.         CONST
  266.             _Unimplemented = $A89F;
  267. {$ENDC}
  268.     BEGIN
  269.         IF (tType = ToolTrap) & (gMac.machineType > envMachUnknown) & (gMac.machineType < envMacII) THEN BEGIN        {it's a 512KE, Plus, or SE}
  270.             tNumber := BAND(tNumber, $03FF);
  271.             IF tNumber > $01FF THEN                            {which means the tool traps}
  272.                 tNumber := _Unimplemented;                    {only go to $01FF}
  273.         END;
  274.         TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(_Unimplemented);
  275.     END; {TrapAvailable}
  276.  
  277. {$S Main}
  278.     FUNCTION GetNewFontSize: INTEGER;
  279. {  Display an alert that lets the user choose an unlisted font size }
  280.         CONST
  281.             rFontSelect = 130;
  282.             kSizeItem = 4;
  283.         VAR
  284.             itemHit, theType, oldSize: INTEGER;
  285.             message: Str255;
  286.             sizeDlg: DialogPtr;
  287.             itemHdl: Handle;
  288.             itembox: Rect;
  289.             sizeNum: LONGINT;
  290.     BEGIN { GetNewFontSize }
  291.         oldSize := gFontSize;
  292.         sizeDlg := GetNewDialog(rFontSelect, NIL, WindowPtr(-1));
  293.         IF sizeDlg <> NIL THEN BEGIN
  294.             NumToString(gFontSize, message);
  295.             GetDItem(sizeDlg, kSizeItem, theType, itemHdl, itembox);
  296.             SetIText(itemHdl, message);
  297.             ShowWindow(sizeDlg);
  298.             REPEAT
  299.                 ModalDialog(NIL, itemHit);
  300.             UNTIL (itemHit = OK) OR (itemHit = Cancel);
  301.             IF itemHit = OK THEN BEGIN
  302.                 GetDItem(sizeDlg, kSizeItem, theType, itemHdl, itembox);
  303.                 GetIText(itemHdl, message);
  304.                 StringToNum(message, sizeNum);
  305.                 GetNewFontSize := sizeNum;
  306.             END
  307.             ELSE
  308.                 GetNewFontSize := oldSize;
  309.             DisposDialog(sizeDlg);
  310.         END
  311.         ELSE
  312.             GetNewFontSize := oldSize;
  313.     END; { GetNewFontSize }
  314.  
  315. {$S Main}
  316.     PROCEDURE AdjustTE (window: WindowPtr);
  317. {    Scroll the TERec around to match up to the potentially updated scrollbar}
  318. {    values. This is really useful when the window resizes such that the}
  319. {    scrollbars become inactive and the TERec had been previously scrolled. }
  320.         VAR
  321.             value: INTEGER;
  322.  
  323.     BEGIN { AdjustTE }
  324.         WITH DocumentPeek(window)^ DO BEGIN
  325.             TEScroll((docTE^^.viewRect.left - docTE^^.destRect.left) - GetCtlValue(docHScroll), (docTE^^.viewRect.top - docTE^^.destRect.top) - GetCtlValue(docVScroll), docTE);
  326.         END; { with }
  327.     END; { AdjustTE }
  328.  
  329. {$S Main}
  330.     PROCEDURE AdjustScrollSizes (window: WindowPtr);
  331.  
  332. {    Re-calculate the position and size of the viewRect and the scrollbars.}
  333. {     kScrollTweek compensates for off-by-one requirements of the scrollbars}
  334. {    to have borders coincide with the growbox. }
  335.  
  336.         VAR
  337.             teRect: Rect;
  338.  
  339.     BEGIN { AdjustScrollSizes }
  340.         GetTERect(window, teRect); {start with teRect}
  341.         WITH DocumentPeek(window)^, window^.portRect DO BEGIN
  342.             docTE^^.viewRect := teRect;
  343.  
  344.         { AdjustViewRect(docTE) was removed--no longer needed }
  345.  
  346.             MoveControl(docVScroll, right - kScrollbarAdjust, -1);
  347.             SizeControl(docVScroll, kScrollbarWidth, (bottom - top) - (kScrollbarAdjust - kScrollTweek));
  348.             MoveControl(docHScroll, -1, bottom - kScrollbarAdjust);
  349.             SizeControl(docHScroll, (right - left) - (kScrollbarAdjust - kScrollTweek), kScrollbarWidth);
  350.         END; { with }
  351.     END; { AdjustScrollSizes }
  352.  
  353. {$S Main}
  354.     PROCEDURE AdjustScrollbars (window: WindowPtr; needsResize: BOOLEAN);
  355.  
  356. {    Turn off the controls by jamming a zero into their contrlVis fields }
  357. {    (HideControl erases them and we don't want that). If the controls are to }
  358. {    be resized as well, call the procedure to do that, then call the procedure }
  359. {    to adjust the maximum and current values. Finally re-enable the controls}
  360. {    by jamming a $FF in their contrlVis fields. }
  361.  
  362.         VAR
  363.             oldMax, oldVal: INTEGER;
  364.  
  365.     BEGIN { AdjustScrollbars }
  366.         WITH DocumentPeek(window)^ DO BEGIN
  367.             docVScroll^^.contrlVis := kControlInvisible; { turn them off }
  368.             docHScroll^^.contrlVis := kControlInvisible;
  369.             IF needsResize THEN                            { move and size if needed }
  370.                 AdjustScrollSizes(window);
  371.             AdjustScrollValues(window, NOT needsResize); { fool with max and current value }
  372.         { Now, restore visibility in case we never had to ShowControl during adjustment }
  373.             docVScroll^^.contrlVis := kControlVisible; { turn them on }
  374.             docHScroll^^.contrlVis := kControlVisible;
  375.         END;
  376.     END; { AdjustScrollbars }
  377.  
  378. {$S Main}
  379. {$PUSH}
  380.  {$Z+}
  381.     PROCEDURE PascalClikLoop;
  382.  
  383. {    Gets called from our assembly language routine, AsmClikLoop, which is in}
  384. {     turn called by the TEClick toolbox routine. Saves the windows clip region,}
  385. {     sets it to the portRect, adjusts the scrollbar values to match the TE scroll}
  386. {     amount, then restores the clip region. }
  387.  
  388.         VAR
  389.             window: WindowPtr;
  390.             region: RgnHandle;
  391.  
  392.     BEGIN { PascalClikLoop }
  393.         window := FrontWindow;
  394.         region := NewRgn;
  395.         GetClip(region); { save the old clip }
  396.         ClipRect(window^.portRect); { set the new clip }
  397.         AdjustScrollValues(window, TRUE); { pass TRUE for canRedraw }
  398.         SetClip(region); { restore the old clip }
  399.         DisposeRgn(region);
  400.     END; { PascalClikLoop }
  401. {$POP}
  402.  
  403. {$S Main}
  404. {$PUSH}
  405.  {$Z+}
  406.     FUNCTION GetOldClikLoop: ProcPtr;
  407.  
  408. {    Gets called from our assembly language routine, AsmClikLoop, which is in}
  409. {    turn called by the TEClick toolbox routine. It returns the address of the}
  410. {    default clikLoop routine that was put into the TERec by TEAutoView to}
  411. {    AsmClikLoop so that it can call it. }
  412.  
  413.     BEGIN { GetOldClikLoop }
  414.         GetOldClikLoop := DocumentPeek(FrontWindow)^.docClik;
  415.     END; { GetOldClikLoop }
  416. {$POP}
  417.  
  418.     PROCEDURE AsmClikLoop;
  419.     EXTERNAL;
  420.  
  421. {    A reference to our assembly language routine that gets attached to the clikLoop}
  422. {    field of our TE record. }
  423.  
  424. (*------------------------------------------------------------------------------*)
  425. {$S Main}
  426.     PROCEDURE Set_init_position;
  427.     BEGIN { Set_init_position }
  428.         gSelStart := 0;
  429.         gSelEnd := 0;
  430.         gInitWndPos.h := (kNewWindowOffset * gNumDocuments) MOD 172 + 10;
  431.         gInitWndPos.v := (kNewWindowOffset * gNumDocuments) MOD 172 + 45;
  432.         gInitWndSize.h := 400;
  433.         gInitWndSize.v := 300;
  434.         gInitScrollVal := 0;
  435.         gInitScrollMax := 0;
  436.     END;    (* Set_init_position *)
  437.  
  438. (*------------------------------------------------------------------------------*)
  439. {$S Main}
  440.     PROCEDURE Read_position (prevWDRefNum: INTEGER; prevFileName: Str255);
  441.         VAR
  442.             refNum: INTEGER;
  443.             prevPosHdl: WindowPosHandle;
  444.     BEGIN    { Read_position }
  445.         Set_init_position;
  446.  
  447.         refNum := OpenRFPerm(prevFileName, prevWDRefNum, fsRdPerm);
  448.         IF (refNum <> -1) THEN BEGIN
  449.         (* read in window position and selection range *)
  450.             prevPosHdl := WindowPosHandle(Get1Resource(kStyleResType, kWndPosResID));
  451.             IF prevPosHdl <> NIL THEN BEGIN
  452.                 HNoPurge(Handle(prevPosHdl));
  453.                 IF (PtInRgn(prevPosHdl^^.wndPos, gGrayRgn)) THEN BEGIN
  454.                     gSelStart := prevPosHdl^^.selStart;
  455.                     gSelEnd := prevPosHdl^^.selEnd;
  456.                     gInitWndPos := prevPosHdl^^.wndPos;
  457.                     gInitWndSize := prevPosHdl^^.wndSize;
  458.                     gInitScrollVal := prevPosHdl^^.scrollVal;
  459.                     gInitScrollMax := prevPosHdl^^.scrollMax;
  460.                 END;
  461.             END;
  462.         END;
  463.         CloseResFile(refNum);
  464.     END;    (* Read_position *)
  465.  
  466. (*------------------------------------------------------------------------------*)
  467. {$S Main}
  468.     PROCEDURE ReadFile (myFType: INTEGER; vRefNum: INTEGER; fName: Str255);
  469.         VAR
  470.             error: OSErr;
  471.             fileNumber: INTEGER;
  472.             textLength: LongInt;
  473.             buffPtr: Ptr;
  474.             tempRect: Rect;
  475.     BEGIN
  476.         Read_position(vRefNum, fName);
  477.         DoNew;
  478.         SetWTitle(gTheActiveWindow, fName);    (*set correct window title*)
  479.         DocumentPeek(gTheActiveWindow)^.WDRefNum := vRefNum;
  480.         DocumentPeek(gTheActiveWindow)^.fileName := fName;
  481.  
  482.         error := FSOpen(fName, vRefNum, fileNumber);       (*open disk file*)
  483.         error := GetEOF(fileNumber, textLength);            (*find length of data in file*)
  484.         IF (textLength > $7FFF) THEN
  485.             textLength := $7FFF;  (*only read first 32k of text*)
  486.         error := SetFPos(fileNumber, fsFromStart, 0); (*set mark at beginning of file*)
  487.         buffPtr := NewPtr(textLength);
  488.         error := FSRead(fileNumber, textLength, buffPtr);
  489.         error := FSClose(fileNumber);                                 (*close file for safety*)
  490.         TESetText(buffPtr, textLength, gTextH);
  491.         DisposPtr(buffPtr);                                                (*garbage collect*)
  492.  
  493.         TECalText(gTextH);                                  (*calc line starts in TERecord*)
  494.         TESetSelect(gSelStart, gSelEnd, gTextH);                         (*Set insertion point*)
  495.         SetRect(tempRect, 0, 0, 0, 0);
  496.         ClipRect(tempRect);                   (* Close clipping region to remove flicker *)
  497.         AdjustScrollValues(gTheActiveWindow, TRUE);
  498.         AdjustTE(gTheActiveWindow);
  499.         ClipRect(gTheActiveWindow^.portRect);
  500.         InvalRect(gTheActiveWindow^.portRect);
  501.     END;    (* ReadFile *)
  502.  
  503.     FUNCTION MyDlgHook (theItem: INTEGER; theDialog: DialogPtr; CFP: SFParamBlock; VAR changedFlag: Boolean; unused: LongInt): INTEGER;
  504.     BEGIN
  505.         IF theItem = 6 THEN
  506.             IF gFirstMyDlgCall THEN BEGIN
  507.                 CFP.AllowFlags := allowText;
  508.                 changedFlag := TRUE;
  509.                 gFirstMyDlgCall := FALSE;
  510.             END;
  511.         MyDlgHook := theItem;
  512.     END;    (* MyDlgHook *)
  513.  
  514. {$S Main}
  515.     PROCEDURE BigBadError (error: INTEGER);
  516.     BEGIN
  517.         AlertUser(error, 0);
  518.         ExitToShell;
  519.     END;
  520.  
  521. {$S Initialize}
  522.     PROCEDURE Initialize;
  523.  
  524. {    Set up the whole world, including global variables, Toolbox managers,}
  525. {     menus, and a single blank document.}
  526.  
  527. {If an error is detected, instead of merely doing an ExitToShell,}
  528. { which leaves the user without much to go on, we call AlertUser, which puts}
  529. { up a simple alert that just says an error occurred and then calls ExitToShell.}
  530. { Since there is no other cleanup needed at this point if an error is detected,}
  531. { this form of error- handling is acceptable. If more sophisticated error recovery}
  532. { is needed, an exception mechanism, such as is provided by Signals, can be used.}
  533.         CONST
  534.         { ———— Defines for XTND resources ———— }
  535.             clarisNames = 25003;    { Claris names STR# resource }
  536.             clarisFolder = 1;
  537.             xtndNames = 25004;    { XTND names STR# resource }
  538.             clarisTranslators = 1;
  539.             xtndSystem = 2;
  540.  
  541.         VAR
  542.             menuBar: Handle;
  543.             total, contig: LongInt;
  544.             ignoreResult: BOOLEAN;
  545.             event: EventRecord;
  546.             count, ignoreError: INTEGER;
  547.             XTNDSystemName, ClarisFolderName: Str255;
  548.     BEGIN { Initialize }
  549.         gInBackground := FALSE;
  550.  
  551.         InitGraf(@thePort);
  552.         InitFonts;
  553.         InitWindows;
  554.         InitMenus;
  555.         TEInit;
  556.         InitDialogs(NIL);
  557.         InitCursor;
  558.  
  559.         FOR count := 1 TO 3 DO
  560.             ignoreResult := EventAvail(everyEvent, event);
  561.         ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
  562.         IF gMac.machineType < 0 THEN
  563.             BigBadError(eWrongMachine);
  564.         gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  565.  
  566.         IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN
  567.             BigBadError(eSmallSize);
  568.         PurgeSpace(total, contig);
  569.         IF total < kMinSpace THEN
  570.             IF UnloadScrap <> noErr THEN
  571.                 BigBadError(eNoMemory)
  572.             ELSE BEGIN
  573.                 PurgeSpace(total, contig);
  574.                 IF total < kMinSpace THEN
  575.                     BigBadError(eNoMemory);
  576.             END; { if }
  577.  
  578.         menuBar := GetNewMBar(rMenuBar); { read menus into menu bar }
  579.         IF menuBar = NIL THEN
  580.             BigBadError(eNoMemory);
  581.         SetMenuBar(menuBar); { install menus }
  582.         DisposHandle(menuBar);
  583.         AddResMenu(GetMHandle(mApple), 'DRVR');    { add DA names to Apple menu }
  584.         AddResMenu(GetMHandle(mFont), 'FONT'); { add Font names to Font Menu }
  585.         DrawMenuBar;
  586.         gNumDocuments := 0;
  587.  
  588.     { do other initialization here }
  589.     { set up printer stuff-this will allow the default pageSetup parameters to be used, so if}
  590. {      the used decides to print with out using pageSetup everything will be okay }
  591.  
  592.         gPrinterRecord := THPrint(NewHandle(SizeOF(TPrint))); {allocate a print record}
  593.         IF gPrinterRecord <> NIL THEN BEGIN {if we're successful then setup the default settings}
  594.             PrOpen; {open the record }
  595.             PrintDefault(gPrinterRecord); { load in default settings }
  596.             PrClose; { close it up }
  597.         END; { if }
  598.  
  599.     { one-time initialization of the XTND Library… }
  600.         GetIndString(XTNDSystemName, xtndNames, xtndSystem);
  601.         GetIndString(ClarisFolderName, clarisNames, clarisFolder);
  602.  
  603.         gxtErr := XTNDInitTranslators(kTransVersion, XTNDSystemName, ClarisFolderName);
  604.         IF gxtErr <> noErr THEN BEGIN
  605.             AlertUser(eNoXTND, gxtErr);
  606.             gXTNDAvail := FALSE;
  607.         END
  608.         ELSE BEGIN
  609.             gXTNDAvail := TRUE;
  610.             gMyFileType[1].Version := 2;
  611.             gMyFileType[1].TranslatorType := 'FLTI';
  612.             gMyFileType[1].CodeResID := 0;
  613.             gMyFileType[1].FDIFResID := -1;
  614.             gMyFileType[1].NumVersBytes := 0;
  615.             gMyFileType[1].PathLength := 0;
  616.             gMyFileType[1].Flags := 0;
  617.             gMyFileType[1].NumMatches := 1;
  618.             gMyFileType[1].Matches[0].DocCreator := 'XTND';
  619.             gMyFileType[1].Matches[0].DocType := 'TEXT';
  620.             gMyFileType[1].Matches[0].ExactMatch := FALSE;
  621.             gMyFileType[1].Matches[0].creatorAndTypeMask := 0;
  622.             gMyFileType[1].Name := 'Text';
  623.             Load_stored := 1;
  624.             Save_stored := 1;
  625.         END;
  626.  
  627.         DoNew; { create a single empty document }
  628.     END; {Initialize}
  629.  
  630. {$S Main}
  631.     PROCEDURE PrintText (hTE: TEHandle);
  632.  
  633. {    Prints the edit record. Opens a printer port, calculates the numbers of lines}
  634. {    per page (it may be different for each page depending on the the text styles) and}
  635. {    then calls TEUpdate for the page, scroll a page and TEUpdate, etc. }
  636.  
  637.         CONST
  638.             Margins = 20;         { page margins }
  639.  
  640.         VAR
  641.             totalLines: INTEGER;    { number of lines in text }
  642.             rView: Rect;        { viewRect for TERect }
  643.             oldPort: grafPtr;    { hold original grafPtr }
  644.             oldView: Rect;        { hold original viewRect }
  645.             oldDest: Rect;        { hold original destRect }
  646.             totalHeight: INTEGER;    { lineHeight for TERec }
  647.             currentLine: INTEGER;    { what line are we on }
  648.             scrollAmount: INTEGER;    { how much we scroll by }
  649.             zeroRect: Rect;        { 0,0,0,0 rect used in clipRect }
  650.  
  651.             thePrinterStatus: TPrStatus; { printer status }
  652.             openPrintManager: BOOLEAN;    { flag if print manager can be opened okay }
  653.             abort: BOOLEAN;    { flag if cmd-period is hit to exit routine }
  654.             viewHeight: INTEGER;    { temp that has the viewRect height+1 to test conditions }
  655.  
  656.     BEGIN { PrintText }
  657.         OpenPrintManager := FALSE; {printer not open yet}
  658.         IF gPrinterRecord <> NIL THEN BEGIN { do we have a legitimate record?}
  659.             PrOpen; {open mr. print record if okay}
  660.             IF PrJobDialog(gPrinterRecord) THEN BEGIN {bring up job dialog}
  661.                 GetPort(oldPort); { save the old stuff to restore later }
  662.                 oldView := hTE^^.viewRect;
  663.                 oldDest := hTE^^.destRect;
  664.                 gPrinterPort := PrOpenDoc(gPrinterRecord, NIL, NIL);
  665.                 OpenPrintManager := (PrError = noErr);
  666.             END; { if }
  667.         END; { if }
  668.  
  669.         IF OpenPrintManager THEN BEGIN
  670.             SetPort(grafPtr(gPrinterPort)); { printer port is now the current port }
  671.             SetRect(zeroRect, 0, 0, 0, 0);
  672.  
  673.             rView := gPrinterRecord^^.PrInfo.rPage; { get the size of the page rectangle }
  674.             InsetRect(rView, Margins, Margins);  { adjust it for the margins }
  675.             hTE^^.inPort := GrafPtr(gPrinterPort); { force TE to look at the printer port }
  676.             hTE^^.destRect := rView;
  677.             hTE^^.viewRect := rView; { set new view and dest rects to the TERec }
  678.             TECalText(hTE); { recalculate our lineStarts array with the new rects }
  679.             totalLines := hTE^^.nLines; { get the number of lines in the newly sized TERec }
  680.             totalHeight := TEGetHeight(totalLines, 0, hTE);
  681.             hTE^^.destRect.bottom := hTE^^.destRect.top + totalHeight; { how tall our destRect is }
  682.  
  683.             abort := FALSE;
  684.             currentLine := 1; { TextEdit sez that TEGetHeight is 1 not 0 based }
  685.  
  686.             WHILE (NOT (abort) AND (currentLine <= totalLines)) DO BEGIN
  687.                 PrOpenPage(gPrinterPort, NIL);
  688.                 scrollAmount := 0;
  689.                 ClipRect(gPrinterRecord^^.PrInfo.rPage); { Open clipping so text will be drawn }
  690.  
  691.                 viewHeight := hTE^^.viewRect.bottom - hTE^^.viewRect.top + 1;
  692.  
  693.             { figure out how many lines there are per page }
  694.                 WHILE (((scrollAmount + TEGetHeight(currentLine, currentLine, hTE)) <= viewHeight) AND (currentLine <= totalLines)) DO BEGIN
  695.                     scrollAmount := scrollAmount + TEGetHeight(currentLine, currentLine, hTE);
  696.                     currentLine := currentLine + 1;
  697.                 END; { while }
  698.  
  699.                 hTE^^.viewRect.bottom := scrollAmount + Margins; { Add margins since top has a margin }
  700.                 TEDeactivate(hTE); { Deactive the edit record so we don't print the cursor or selection range }
  701.                 TEUpdate(hTE^^.viewRect, hTE); { print the page }
  702.                 ClipRect(zeroRect); { Close clipping so that TEScroll doesn't redraw the text }
  703.                 TEScroll(0, -scrollAmount, hTE); { scroll the page so we can print the next one }
  704.                 hTE^^.viewRect.bottom := rView.bottom; { reset bottom to full page }
  705.  
  706.                 IF prError = iPrAbort THEN
  707.                     abort := TRUE;
  708.                 PrClosePage(gPrinterPort); { close everything up }
  709.             END; { while }
  710.  
  711.             PrCloseDoc(gPrinterPort);
  712.             IF (gPrinterRecord^^.prJob.bJDocLoop = bSpoolLoop) AND (PrError = noErr) THEN
  713.                 PrPicFile(gPrinterRecord, NIL, NIL, NIL, thePrinterStatus);
  714.             PrClose;
  715.             SetPort(oldPort);
  716.             hTE^^.inPort := oldPort;
  717.             hTE^^.viewRect := oldView; { restore the old stuff when we are done }
  718.             hTE^^.destRect := oldDest;
  719.             TEUpdate(hTE^^.viewRect, hTE); { update everything after resetting the port }
  720.         END; { if }
  721.     END; { PrintText }
  722.  
  723. {$S Main}
  724.     PROCEDURE Terminate;
  725.  
  726. {    Clean up the application and exit. We close all of the windows so that}
  727. {    they can update their documents, if any. }
  728.  
  729.         VAR
  730.             aWindow: WindowPtr;
  731.             closed: BOOLEAN;
  732.  
  733.     BEGIN { Terminate }
  734.         closed := TRUE;
  735.         REPEAT
  736.             aWindow := FrontWindow; { get the current front window }
  737.             IF aWindow <> NIL THEN
  738.                 closed := DoCloseWindow(aWindow);    { close this window }
  739.         UNTIL (NOT closed) | (aWindow = NIL); { do all windows }
  740.         IF closed THEN
  741.             ExitToShell; { exit if no cancellation }
  742.     END; { Terminate }
  743.  
  744. {$S Main}
  745.     PROCEDURE AdjustMenus;
  746.  
  747.         VAR
  748.             window: WindowPtr;
  749.             menu: MenuHandle;
  750.             offset: LONGINT;
  751.             undo: BOOLEAN;    { flag to enable/disable undo command }
  752.             cutCopyClear: BOOLEAN;    { flag to enable/disable editing commands }
  753.             paste: BOOLEAN;
  754.             selectAll: BOOLEAN;
  755.  
  756.             doPrint: BOOLEAN;    { flag to enable/disable printing item }
  757.  
  758.             te: TEHandle;    { local te handle }
  759.             mode: INTEGER;    { current style }
  760.  
  761.     BEGIN
  762.         window := FrontWindow;
  763.  
  764.         menu := GetMHandle(mFile);
  765.         IF gNumDocuments < kMaxOpenDocuments THEN BEGIN
  766.             EnableItem(menu, iNew);{ New is enabled when we can open more documents }
  767.             EnableItem(menu, iOpen);{ Open is enabled when we can open more documents }
  768.         END
  769.         ELSE BEGIN
  770.             DisableItem(menu, iOpen);
  771.             DisableItem(menu, iNew);
  772.         END;
  773.  
  774.         IF window <> NIL THEN BEGIN { Close/Save are enabled when there is a window to close }
  775.             EnableItem(menu, iClose);
  776.             EnableItem(menu, iSave);
  777.             EnableItem(menu, iSaveAs);
  778.         END
  779.         ELSE BEGIN
  780.             DisableItem(menu, iClose);
  781.             DisableItem(menu, iSave);
  782.             DisableItem(menu, iSaveAs);
  783.         END;
  784.  
  785.         menu := GetMHandle(mEdit);
  786.         undo := FALSE;
  787.         cutCopyClear := FALSE;
  788.         paste := FALSE;
  789.         selectAll := FALSE;
  790.         doPrint := FALSE;
  791.  
  792.         IF IsDAWindow(window) THEN BEGIN
  793.             undo := TRUE; { all editing is enabled for DA windows }
  794.             cutCopyClear := TRUE;
  795.             paste := TRUE;
  796.             selectAll := TRUE;
  797.         END
  798.         ELSE IF IsAppWindow(window) THEN BEGIN
  799.             WITH DocumentPeek(window)^.docTE^^ DO
  800.                 IF selStart < selEnd THEN BEGIN
  801.                     cutCopyClear := TRUE;
  802.                 END; { if }
  803.                 { Cut, Copy, and Clear is enabled for app. windows with selections }
  804.             IF GetScrap(NIL, 'TEXT', offset) > 0 THEN
  805.                 paste := TRUE; { Paste is enabled for app. windows }
  806.  
  807.             selectAll := TRUE;
  808.             doPrint := TRUE;
  809.  
  810.             mode := doFace;
  811.             menu := GetMHandle(mStyle);
  812.             IF TEContinuousStyle(mode, gTxStyle, DocumentPeek(window)^.docTE) THEN BEGIN
  813.                 CheckItem(menu, iPlain, gTxStyle.tsface = []);
  814.                 CheckItem(menu, iBold, bold IN gTxStyle.tsFace);
  815.                 CheckItem(menu, iItalic, italic IN gTxStyle.tsFace);
  816.                 CheckItem(menu, iUnderline, underline IN gTxStyle.tsFace);
  817.                 CheckItem(menu, iOutline, outline IN gTxStyle.tsFace);
  818.                 CheckItem(menu, iShadow, shadow IN gTxStyle.tsFace);
  819.             END
  820.             ELSE BEGIN
  821.                 CheckItem(menu, iPlain, FALSE);
  822.                 CheckItem(menu, iBold, FALSE);
  823.                 CheckItem(menu, iItalic, FALSE);
  824.                 CheckItem(menu, iUnderline, FALSE);
  825.                 CheckItem(menu, iOutline, FALSE);
  826.                 CheckItem(menu, iShadow, FALSE);
  827.             END; { if }
  828.  
  829.         END; { if }
  830.         menu := GetMHandle(mEdit);
  831.  
  832.         IF undo THEN
  833.             EnableItem(menu, iUndo)
  834.         ELSE
  835.             DisableItem(menu, iUndo);
  836.  
  837.         IF cutCopyClear THEN BEGIN
  838.             EnableItem(menu, iCut);
  839.             EnableItem(menu, iCopy);
  840.             EnableItem(menu, iClear);
  841.         END
  842.         ELSE BEGIN
  843.             DisableItem(menu, iCut);
  844.             DisableItem(menu, iCopy);
  845.             DisableItem(menu, iClear);
  846.         END; { if }
  847.  
  848.  
  849.         IF paste THEN
  850.             EnableItem(menu, iPaste)
  851.         ELSE
  852.             DisableItem(menu, iPaste);
  853.  
  854.         IF selectAll THEN
  855.             EnableItem(menu, iSelectAll)
  856.         ELSE
  857.             DisableItem(menu, iSelectAll);
  858.  
  859.  
  860.         menu := GetMHandle(mFile);
  861.         IF doPrint THEN BEGIN
  862.             EnableItem(menu, iPageSetup);
  863.             EnableItem(menu, iPrint);
  864.         END
  865.         ELSE BEGIN
  866.             DisableItem(menu, iPageSetup);
  867.             DisableItem(menu, iPrint);
  868.         END; { if }
  869.  
  870.     END; { AdjustMenus }
  871.  
  872. {$S Main}
  873.     PROCEDURE DoMenuCommand (menuResult: LONGINT);
  874.  
  875. {    This is called when an item is chosen from the menu bar (after calling}
  876. {    MenuSelect or MenuKey). It does the right thing for each command. }
  877.  
  878.         VAR
  879.             menuID, menuItem: INTEGER;
  880.             itemHit, daRefNum: INTEGER;
  881.             daName: Str255;
  882.  
  883.             tempStr: Str255;
  884.             menu: MenuHandle;
  885.             anIntPtr: ^INTEGER;
  886.  
  887.             ignoreResult, saveErr: OSErr;
  888.             handledByDA: BOOLEAN;
  889.             te: TEHandle;
  890.             window: WindowPtr;
  891.             ignore: BOOLEAN;
  892.             aHandle: Handle;
  893.             oldSize, newSize: LONGINT;
  894.             total, contig: LONGINT;
  895.  
  896.  
  897.     BEGIN
  898.         window := FrontWindow;
  899.         menuID := HiWrd(menuResult); { use built-ins (for efficiency)... }
  900.         menuItem := LoWrd(menuResult); { to get menu item number and menu number }
  901.         te := DocumentPeek(window)^.docTE;
  902.  
  903.         CASE menuID OF
  904.  
  905.             mApple: 
  906.                 CASE menuItem OF
  907.                     iAbout:                {bring up alert for About}
  908.                         itemHit := Alert(rAboutAlert, NIL);
  909.                     OTHERWISE BEGIN        { all non-About items in this menu are DAs }
  910.                         GetItem(GetMHandle(mApple), menuItem, daName);
  911.                         daRefNum := OpenDeskAcc(daName);
  912.                     END; { otherwise }
  913.                 END; { case }
  914.  
  915.             mFile: 
  916.                 CASE menuItem OF
  917.                     iNew: 
  918.                         DoNew;
  919.                     iOpen:  BEGIN
  920.                         SetCursor(GetCursor(watchCursor)^^);
  921.                         DoOpen;
  922.                     END;
  923.  
  924.                     iClose: 
  925.                         ignore := DoCloseWindow(window);
  926.  
  927.                     iSave: 
  928.                         DoSave(FALSE);
  929.  
  930.                     iSaveAs: 
  931.                         DoSave(TRUE);
  932.  
  933.                     iPageSetup:  BEGIN
  934.                         PrOpen;
  935.                         IF PrError = noErr THEN
  936.                             ignore := PrStlDialog(gPrinterRecord);
  937.                         PrClose;
  938.                     END; { iPageSetup }
  939.                     iPrint: 
  940.                         PrintText(te);
  941.                     iQuit: 
  942.                         Terminate;
  943.                 END; { case }
  944.  
  945.             mEdit:  BEGIN                { call SystemEdit for DA editing & MultiFinder }
  946.                 IF NOT SystemEdit(menuItem - 1) THEN BEGIN
  947.                     CASE menuItem OF
  948.  
  949.                         iCut:  BEGIN
  950.                             IF ZeroScrap = noErr THEN BEGIN
  951.                                 PurgeSpace(total, contig);
  952.                                 IF (te^^.selEnd - te^^.selStart) + kTESlop > contig THEN
  953.                                     AlertUser(eNoSpaceCut, 0)
  954.                                 ELSE BEGIN
  955.                                     TECut(te);
  956.                                 END; { if }
  957.                             END; { if }
  958.                         END; { iCut }
  959.  
  960.                         iCopy:  BEGIN
  961.                             IF ZeroScrap = noErr THEN BEGIN
  962.                                 TECopy(te);
  963.                             END; { if }
  964.                         END; { iCopy }
  965.  
  966.                         iPaste:  BEGIN
  967.                             IF TEGetScrapLen + (te^^.teLength - (te^^.selEnd - te^^.selStart)) > kMaxTELength THEN
  968.                                 AlertUser(eExceedPaste, 0)
  969.                             ELSE BEGIN
  970.                                 aHandle := Handle(TEGetText(te));
  971.                                 oldSize := GetHandleSize(aHandle);
  972.                                 newSize := oldSize + TEGetScrapLen + kTESlop;
  973.                                 SetHandleSize(aHandle, newSize);
  974.                                 saveErr := MemError;
  975.                                 SetHandleSize(aHandle, oldSize);
  976.                                 IF saveErr <> noErr THEN
  977.                                     AlertUser(eNoSpacePaste, 0)
  978.                                 ELSE
  979.                                     TEStylPaste(te);
  980.                             END; { if }
  981.                         END; { iPaste }
  982.  
  983.                         iClear: 
  984.                             TEDelete(te);
  985.  
  986.                         iSelectAll: 
  987.                             TESetSelect(0, te^^.teLength, te);
  988.  
  989.                     END; { case }
  990.                     IF menuItem <> iCopy THEN
  991.                         AdjustScrollBars(window, FALSE);
  992.                 END; { if }
  993.             END; { mEdit }
  994.  
  995.             mFont:  BEGIN { mFont }
  996.                 GetItem(GetMHandle(mFont), menuItem, gFontName);
  997.                 getFNum(gFontName, gFontID);
  998.                 gTxStyle.tsFont := gFontID;
  999.                 TESetStyle(doFont, gTxStyle, true, te);
  1000.                 AdjustScrollBars(window, FALSE);
  1001.             END; { mFont }
  1002.  
  1003.             mFontSize:  BEGIN { mFontSize }
  1004.                 CASE menuItem OF
  1005.                     iNine: 
  1006.                         gFontSize := 9;
  1007.                     iTen: 
  1008.                         gFontSize := 10;
  1009.                     iTwelve: 
  1010.                         gFontSize := 12;
  1011.                     iFourteen: 
  1012.                         gFontSize := 14;
  1013.                     iEighteen: 
  1014.                         gFontSize := 18;
  1015.                     iTwoFour: 
  1016.                         gFontSize := 24;
  1017.                     iOther: 
  1018.                         gFontSize := GetNewFontSize;
  1019.                 END; { case }
  1020.                 gTxStyle.tsSize := gFontSize;
  1021.                 TESetStyle(doSize, gTxStyle, TRUE, te);
  1022.                 AdjustScrollBars(window, FALSE);
  1023.             END; { mFontSize }
  1024.  
  1025.             mStyle:  BEGIN { mStyle }
  1026.                 WITH gTxStyle DO BEGIN
  1027.                     CASE menuItem OF
  1028.                         iPlain:  BEGIN
  1029.                             anIntPtr := @gTxStyle.tsFace; { as per Tech Note #131 }
  1030.                             anIntPtr^ := 0;
  1031.                             tsFace := [];
  1032.                         END;
  1033.                         iBold: 
  1034.                             tsFace := [bold];
  1035.                         iItalic: 
  1036.                             tsFace := [italic];
  1037.                         iUnderline: 
  1038.                             tsFace := [underline];
  1039.                         iOutline: 
  1040.                             tsFace := [outline];
  1041.                         iShadow: 
  1042.                             tsFace := [shadow];
  1043.                     END; { case }
  1044.  
  1045.                     IF menuItem <> 1 THEN
  1046.                         TESetStyle(doFace + doToggle, gTxStyle, TRUE, te)
  1047.                          { if we don't select plain then use doToggle }
  1048.                     ELSE
  1049.                         TESetStyle(doFace, gTxStyle, TRUE, te);
  1050.                         { TESetStyle has problems with plain and doToggle-has no effect!}
  1051. {                          so we need to special case it. }
  1052.                     AdjustScrollBars(window, FALSE);
  1053.                 END; { with }
  1054.             END; { mStyle }
  1055.  
  1056.         END; { case }
  1057.         HiliteMenu(0); { unhighlight what MenuSelect (or MenuKey) hilited }
  1058.     END; { DoMenuCommand }
  1059.  
  1060. {$S Main}
  1061.     PROCEDURE DrawWindow (window: WindowPtr);
  1062.  
  1063. {    Draw the contents of an application window. }
  1064.  
  1065.     BEGIN { DrawWindow }
  1066.         SetPort(window);
  1067.         WITH window^ DO BEGIN
  1068.             EraseRect(portRect); { as per TextEdit chapter of Inside Macintosh }
  1069.             DrawControls(window); { this ordering makes for a better appearance }
  1070.             DrawGrowIcon(window);
  1071.             TEUpdate(portRect, DocumentPeek(window)^.docTE);
  1072.         END; { with }
  1073.     END; { DrawWindow }
  1074.  
  1075. {$S Main}
  1076.     FUNCTION GetSleep: LONGINT;
  1077.  
  1078. {    Calculate a sleep value for WaitNextEvent. This takes into account the things}
  1079. {     that DoIdle does with idle time. }
  1080.  
  1081.         VAR
  1082.             sleep: LONGINT;
  1083.             window: WindowPtr;
  1084.  
  1085.     BEGIN { GetSleep }
  1086.         sleep := MAXLONGINT; { default value for sleep }
  1087.         IF NOT gInBackground THEN BEGIN { if we are in front... }
  1088.             window := FrontWindow; { and the front window is ours... }
  1089.             IF IsAppWindow(window) THEN BEGIN
  1090.                 WITH DocumentPeek(window)^.docTE^^ DO
  1091.                     IF selStart = selEnd THEN { and the selection is an insertion point... }
  1092.                         sleep := GetCaretTime; { we need to blink the insertion point }
  1093.             END; { if }
  1094.         END; { if }
  1095.         GetSleep := sleep;
  1096.     END; { GetSleep }
  1097.  
  1098. {$S Main}
  1099.     PROCEDURE CommonAction (control: ControlHandle; VAR amount: INTEGER);
  1100.  
  1101. {    Common algorithm for setting the new value of a control. It returns the actual amount}
  1102. {    the value of the control changed. Note the pinning is done for the sake of returning}
  1103. {    the amount the control value changed. }
  1104.  
  1105.         VAR
  1106.             value, max: INTEGER;
  1107.             window: WindowPtr;
  1108.  
  1109.     BEGIN { CommonAction }
  1110.         value := GetCtlValue(control); { get current value }
  1111.         max := GetCtlMax(control); { and max value }
  1112.         amount := value - amount;
  1113.         IF amount < 0 THEN
  1114.             amount := 0
  1115.         ELSE IF amount > max THEN
  1116.             amount := max;
  1117.         SetCtlValue(control, amount);
  1118.         amount := value - amount; { calculate true change }
  1119.     END; { CommonAction }
  1120.  
  1121. {$S Main}
  1122.     PROCEDURE VActionProc (control: ControlHandle; part: INTEGER);
  1123.  
  1124. {    Determines how much to change the value of the vertical scrollbar by and how}
  1125. {    much to scroll the TE record. }
  1126.  
  1127.         VAR
  1128.             amount: INTEGER;
  1129.             window: WindowPtr;
  1130.  
  1131.     BEGIN { VActionProc }
  1132.         IF part <> 0 THEN BEGIN
  1133.             window := control^^.contrlOwner;
  1134.             WITH DocumentPeek(window)^, DocumentPeek(window)^.docTE^^ DO BEGIN
  1135.                 CASE part OF
  1136.                     inUpButton, inDownButton: 
  1137.                         amount := 24;
  1138.                     inPageUp, inPageDown: 
  1139.                         amount := viewRect.bottom - viewRect.top; { one page }
  1140.                 END; { case }
  1141.                 IF (part = inDownButton) | (part = inPageDown) THEN
  1142.                     amount := -amount; { reverse direction }
  1143.                 CommonAction(control, amount);
  1144.                 IF amount <> 0 THEN
  1145.                     TEScroll(0, amount, docTE);
  1146.             END; { with }
  1147.         END; { if }
  1148.     END; { VActionProc }
  1149.  
  1150. {$S Main}
  1151.     PROCEDURE HActionProc (control: ControlHandle; part: INTEGER);
  1152.  
  1153. {    Determines how much to change the value of the horizontal scrollbar by and how}
  1154. {    much to scroll the TE record. }
  1155.  
  1156.         VAR
  1157.             amount: INTEGER;
  1158.             window: WindowPtr;
  1159.  
  1160.     BEGIN { HActionProc }
  1161.         IF part <> 0 THEN BEGIN
  1162.             window := control^^.contrlOwner;
  1163.             WITH DocumentPeek(window)^, DocumentPeek(window)^.docTE^^ DO BEGIN
  1164.                 CASE part OF
  1165.                     inUpButton, inDownButton: 
  1166.                         amount := kButtonScroll; { a few pixels }
  1167.                     inPageUp, inPageDown: 
  1168.                         amount := viewRect.right - viewRect.left; { a page }
  1169.                 END; { case }
  1170.                 IF (part = inDownButton) | (part = inPageDown) THEN
  1171.                     amount := -amount; { reverse direction }
  1172.                 CommonAction(control, amount);
  1173.                 IF amount <> 0 THEN
  1174.                     TEScroll(amount, 0, docTE);
  1175.             END; { with }
  1176.         END; { if }
  1177.     END; { HActionProc }
  1178.  
  1179. {$S Main}
  1180.     PROCEDURE DoIdle;
  1181.  
  1182. {    This is called whenever we get an null event or a mouse-moved event.}
  1183. {     It takes care of necessary periodic actions. For this program, it calls TEIdle. }
  1184.  
  1185.         VAR
  1186.             window: WindowPtr;
  1187.  
  1188.     BEGIN { DoIdle }
  1189.         window := FrontWindow;
  1190.         IF IsAppWindow(window) THEN
  1191.             TEIdle(DocumentPeek(window)^.docTE);
  1192.     END; { DoIdle }
  1193.  
  1194. {$S Main}
  1195.     PROCEDURE DoKeyDown (event: EventRecord);
  1196.  
  1197. {    This is called for any keyDown or autoKey events, except when the}
  1198. {    Command key is held down. It looks at the frontmost window to decide what}
  1199. {     to do with the key typed. }
  1200.  
  1201.         VAR
  1202.             window: WindowPtr;
  1203.             key: CHAR;
  1204.             te: TEHandle;
  1205.  
  1206.     BEGIN
  1207.         window := FrontWindow;
  1208.         IF IsAppWindow(window) THEN BEGIN
  1209.             te := DocumentPeek(window)^.docTE;
  1210.             key := CHR(BAnd(event.message, charCodeMask));
  1211.             IF (key = CHR(kDelChar)) | (te^^.teLength - (te^^.selEnd - te^^.selStart) + 1 < kMaxTELength) THEN     { don't count deletes }
  1212.                 BEGIN    { but check haven't gone past }
  1213.                 TEKey(key, te);
  1214.                 AdjustScrollbars(window, FALSE);
  1215.             END
  1216.             ELSE
  1217.                 AlertUser(eExceedChar, 0);
  1218.         END; { if }
  1219.     END; { DoKeyDown }
  1220.  
  1221. {$S Main}
  1222.     PROCEDURE DoContentClick (window: WindowPtr; event: EventRecord);
  1223.  
  1224. {    Called when a mouseDown occurs in the content of a window. }
  1225.  
  1226.         VAR
  1227.             mouse: Point;
  1228.             control: ControlHandle;
  1229.             part, value: INTEGER;
  1230.             shiftDown: BOOLEAN;
  1231.             teRect: Rect;
  1232.  
  1233.     BEGIN { DoContentClick }
  1234.         IF IsAppWindow(window) THEN BEGIN
  1235.             SetPort(window);
  1236.             mouse := event.where; { get the click position }
  1237.             GlobalToLocal(mouse); { convert to local coordinates }
  1238.  
  1239.             GetTERect(window, teRect);
  1240.             IF PtInRect(mouse, teRect) THEN BEGIN
  1241.                 shiftDown := BAnd(event.modifiers, shiftKey) <> 0; { extend if Shift is down }
  1242.                 TEClick(mouse, shiftDown, DocumentPeek(window)^.docTE);
  1243.             END
  1244.             ELSE BEGIN
  1245.                 part := FindControl(mouse, window, control);
  1246.                 WITH DocumentPeek(window)^ DO
  1247.                     CASE part OF
  1248.                         0: 
  1249.                             ;     { do nothing for viewRect case }
  1250.                         inThumb:  BEGIN
  1251.                             value := GetCtlValue(control);
  1252.                             part := TrackControl(control, mouse, NIL);
  1253.                             IF part <> 0 THEN BEGIN
  1254.                                 value := value - GetCtlValue(control);
  1255.                                 IF value <> 0 THEN
  1256.                                     IF control = docVScroll THEN
  1257.                                         TEScroll(0, value, docTE)
  1258.                                     ELSE
  1259.                                         TEScroll(value, 0, docTE);
  1260.                             END; { if }
  1261.                         END; { inThumb }
  1262.                         OTHERWISE    { must be page or button }
  1263.                             IF control = docVScroll THEN
  1264.                                 value := TrackControl(control, mouse, @VActionProc)
  1265.                             ELSE
  1266.                                 value := TrackControl(control, mouse, @HActionProc);
  1267.                     END; { case }
  1268.             END; { if }
  1269.         END; { if }
  1270.     END; { DoContentClick }
  1271.  
  1272. {$S Main}
  1273.     PROCEDURE ResizeWindow (window: WindowPtr);
  1274.  
  1275. {    Called when the window has been resized to fix up the controls and content }
  1276.  
  1277.     BEGIN { ResizeWindow }
  1278.         WITH window^ DO BEGIN
  1279.             AdjustScrollbars(window, TRUE);
  1280.             AdjustTE(window);
  1281.             InvalRect(portRect);
  1282.         END;
  1283.     END; { ResizeWindow }
  1284.  
  1285. {$S Main}
  1286.     PROCEDURE GetLocalUpdateRgn (window: WindowPtr; localRgn: RgnHandle);
  1287.  
  1288. {    Returns the update region in local coordinates }
  1289.  
  1290.     BEGIN { GetLocalUpdateRgn }
  1291.         CopyRgn(WindowPeek(window)^.updateRgn, localRgn); { save old update region }
  1292.         WITH window^.portBits.bounds DO
  1293.             OffsetRgn(localRgn, left, top); { convert to local coords }
  1294.     END; { GetLocalUpdateRgn }
  1295.  
  1296. {$S Main}
  1297.     PROCEDURE DoGrowWindow (window: WindowPtr; event: EventRecord);
  1298.  
  1299. {    Called when a mouseDown occurs in the grow box of an active window. In}
  1300. {     order to eliminate any 'flicker', we want to invalidate only what is}
  1301. {     necessary. Since ResizeWindow invalidates the whole portRect, we save}
  1302. {     the old TE viewRect, intersect it with the new TE viewRect, and}
  1303. {     remove the result from the update region. However, we must make sure}
  1304. {     that any old update region that might have been around gets put back. }
  1305.  
  1306.         VAR
  1307.             growResult: LONGINT;
  1308.             tempRect: Rect;
  1309.             tempRgn: RgnHandle;
  1310.             ignoreResult: BOOLEAN;
  1311.  
  1312.     BEGIN { DoGrowWindow }
  1313.         WITH screenBits.bounds DO
  1314.             SetRect(tempRect, kMinDocDim, kMinDocDim, right, bottom); { set up limiting values }
  1315.         growResult := GrowWindow(window, event.where, tempRect);
  1316.         IF growResult <> 0 THEN  { see if changed size }
  1317.             WITH DocumentPeek(window)^, window^ DO BEGIN
  1318.                 tempRect := docTE^^.viewRect; { save old text box }
  1319.                 tempRgn := NewRgn;
  1320.                 GetLocalUpdateRgn(window, tempRgn); { get localized update region }
  1321.                 SizeWindow(window, LoWrd(growResult), HiWrd(growResult), TRUE);
  1322.                 ResizeWindow(window);
  1323.                 ignoreResult := SectRect(tempRect, docTE^^.viewRect, tempRect); { find what stayed same }
  1324.                 ValidRect(tempRect); { take it out of update }
  1325.                 InvalRgn(tempRgn); { put back any prior update }
  1326.                 DisposeRgn(tempRgn);
  1327.             END; { with }
  1328.     END; { DoGrowWindow }
  1329.  
  1330. {$S Main}
  1331.     PROCEDURE DoZoomWindow (window: WindowPtr; part: INTEGER);
  1332.  
  1333. {    Called when a mouseClick occurs in the zoom box of an active window.}
  1334. {    Everything has to get re-drawn here, so we don't mind that}
  1335. {    ResizeWindow invalidates the whole portRect. }
  1336.  
  1337.     BEGIN { DoZoomWindow }
  1338.         WITH window^ DO BEGIN
  1339.             EraseRect(portRect);
  1340.             ZoomWindow(window, part, (window = FrontWindow));
  1341.             ResizeWindow(window);
  1342.         END; { with }
  1343.     END; { DoZoomWindow }
  1344.  
  1345. {$S Main}
  1346.     PROCEDURE DoUpdate (window: WindowPtr);
  1347.  
  1348. {    This is called when an update event is received for a window.}
  1349. {     It calls DrawWindow to draw the contents of an application window,}
  1350. {     but only if the visRgn is non-empty; for efficiency reasons,}
  1351. {     not because it is required. }
  1352.  
  1353.     BEGIN { DoUpdate }
  1354.         IF IsAppWindow(window) THEN BEGIN
  1355.             BeginUpdate(window); { this sets up the visRgn }
  1356.             IF NOT EmptyRgn(window^.visRgn) THEN    { draw if updating needs to be done }
  1357.                 DrawWindow(window);
  1358.             EndUpdate(window);
  1359.         END; { if }
  1360.     END; { DoUpdate }
  1361.  
  1362. {$S Main}
  1363.     PROCEDURE DoActivate (window: WindowPtr; becomingActive: BOOLEAN);
  1364.  
  1365. {    This is called when a window is activated or deactivated. }
  1366.  
  1367.         VAR
  1368.             tempRgn, clipRgn: RgnHandle;
  1369.             growRect: Rect;
  1370.  
  1371.     BEGIN { DoActivate }
  1372.         IF IsAppWindow(window) THEN
  1373.             WITH DocumentPeek(window)^ DO
  1374.                 IF becomingActive THEN BEGIN
  1375.                 { since we don’t want TEActivate to draw a selection in an area where}
  1376. {                  we’re going to erase and redraw, we’ll clip out the update region}
  1377. {                  before calling it. }
  1378.                     tempRgn := NewRgn;
  1379.                     clipRgn := NewRgn;
  1380.                     GetLocalUpdateRgn(window, tempRgn); { get localized update region }
  1381.                     GetClip(clipRgn);
  1382.                     DiffRgn(clipRgn, tempRgn, tempRgn); { subtract updateRgn from clipRgn }
  1383.                     SetClip(tempRgn);
  1384.                     TEActivate(docTE); { let TE do its thing }
  1385.                     SetClip(clipRgn); { restore the full-blown clipRgn }
  1386.                     DisposeRgn(tempRgn);
  1387.                     DisposeRgn(clipRgn);
  1388.  
  1389.                 {the controls need to be redrawn on activation:}
  1390.                     docVScroll^^.contrlVis := kControlVisible;
  1391.                     docHScroll^^.contrlVis := kControlVisible;
  1392.                     InvalRect(docVScroll^^.contrlRect);
  1393.                     InvalRect(docHScroll^^.contrlRect);
  1394.                 { the growbox needs to be redrawn on activation: }
  1395.                     growRect := window^.portRect;
  1396.                     WITH growRect DO BEGIN
  1397.                         top := bottom - kScrollbarAdjust; { adjust for the scrollbars }
  1398.                         left := right - kScrollbarAdjust;
  1399.                     END; { with }
  1400.                     InvalRect(growRect);
  1401.                 END
  1402.                 ELSE BEGIN
  1403.                     TEDeactivate(docTE);
  1404.                 { the controls should be hidden immediately on deactivation: }
  1405.                     HideControl(docVScroll);
  1406.                     HideControl(docHScroll);
  1407.                 { the growbox should be changed immediately on deactivation: }
  1408.                     DrawGrowIcon(window);
  1409.                 END; { if }
  1410.     END; { DoActivate }
  1411.  
  1412. {$S Main}
  1413.     PROCEDURE GetGlobalMouse (VAR mouse: Point);
  1414.  
  1415. {Get the global coordinates of the mouse. When you call OSEventAvail}
  1416. { it will return either a pending event or a null event. In either case,}
  1417. { the where field of the event record will contain the current position}
  1418. { of the mouse in global coordinates and the modifiers field will reflect}
  1419. { the current state of the modifiers. Another way to get the global}
  1420. { coordinates is to call GetMouse and LocalToGlobal, but that requires}
  1421. { being sure that thePort is set to a valid port.}
  1422.  
  1423.         VAR
  1424.             event: EventRecord;
  1425.  
  1426.     BEGIN
  1427.         IF OSEventAvail(kNoEvents, event) THEN
  1428.             ;    {we aren't interested in any events}
  1429.         mouse := event.where;                    {just the mouse position}
  1430.     END;
  1431.  
  1432. {$S Main}
  1433.     PROCEDURE AdjustCursor (mouse: Point; region: RgnHandle);
  1434.  
  1435. { Change the cursor's shape, depending on its position. This also calculates a region}
  1436. { that includes the cursor for WaitNextEvent. }
  1437.  
  1438.         VAR
  1439.             window: WindowPtr;
  1440.             arrowRgn: RgnHandle;
  1441.             iBeamRgn: RgnHandle;
  1442.             iBeamRect: Rect;
  1443.  
  1444.     BEGIN { AdjustCursor }
  1445.         window := FrontWindow; { we only adjust the cursor when we are in front }
  1446.         IF (NOT gInBackground) AND (NOT IsDAWindow(window)) THEN BEGIN
  1447.         { calculate regions for different cursor shapes}
  1448.             arrowRgn := NewRgn;
  1449.             iBeamRgn := NewRgn;
  1450.  
  1451.         { start with a big, big rectangular region }
  1452.             SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  1453.  
  1454.         { calculate iBeamRgn }
  1455.             IF IsAppWindow(window) THEN BEGIN
  1456.                 iBeamRect := DocumentPeek(window)^.docTE^^.viewRect;
  1457.                 SetPort(window); { make a global version of the viewRect }
  1458.                 WITH iBeamRect DO BEGIN
  1459.                     LocalToGlobal(topLeft);
  1460.                     LocalToGlobal(botRight);
  1461.                 END; { with }
  1462.                 RectRgn(iBeamRgn, iBeamRect);
  1463.                 WITH window^.portBits.bounds DO
  1464.                     SetOrigin(-left, -top);
  1465.                 SectRgn(iBeamRgn, window^.visRgn, iBeamRgn);
  1466.                 SetOrigin(0, 0);
  1467.             END; { if }
  1468.  
  1469.         { subtract other regions from arrowRgn }
  1470.             DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  1471.  
  1472.         {change the cursor and the region parameter}
  1473.             IF PtInRgn(mouse, iBeamRgn) THEN BEGIN
  1474.                 SetCursor(GetCursor(iBeamCursor)^^);
  1475.                 CopyRgn(iBeamRgn, region);
  1476.             END
  1477.             ELSE BEGIN
  1478.                 SetCursor(arrow);
  1479.                 CopyRgn(arrowRgn, region);
  1480.             END; { if }
  1481.  
  1482.         { get rid of our local regions }
  1483.             DisposeRgn(arrowRgn);
  1484.             DisposeRgn(iBeamRgn);
  1485.         END; { if }
  1486.     END; { AdjustCursor }
  1487.  
  1488. {$S Main}
  1489.     PROCEDURE DoEvent (event: EventRecord);
  1490.  
  1491. {    Do the right thing for an event. Determine what kind of event it is, and call}
  1492. {     the appropriate routines. }
  1493.  
  1494.         VAR
  1495.             part, err: INTEGER;
  1496.             window: WindowPtr;
  1497.             key: CHAR;
  1498.             ignore: BOOLEAN;
  1499.             aPoint: Point;
  1500.  
  1501.     BEGIN { DoEvent }
  1502.         CASE event.what OF
  1503.             nullEvent: 
  1504.                 DoIdle;
  1505.             mouseDown:  BEGIN
  1506.                 part := FindWindow(event.where, window);
  1507.                 CASE part OF
  1508.  
  1509.                     inMenuBar:  BEGIN
  1510.                         AdjustMenus;
  1511.                         DoMenuCommand(MenuSelect(event.where));
  1512.                     END; { inMenuBar }
  1513.  
  1514.                     inSysWindow: 
  1515.                         SystemClick(event, window);
  1516.  
  1517.                     inContent: 
  1518.                         IF window <> FrontWindow THEN BEGIN
  1519.                             SelectWindow(window);
  1520.                         {DoEvent(event);}
  1521.     {use this line for "do first click"}
  1522.                         END
  1523.                         ELSE
  1524.                             DoContentClick(window, event);
  1525.  
  1526.                     inDrag: 
  1527.                         DragWindow(window, event.where, screenBits.bounds);
  1528.  
  1529.                     inGrow: 
  1530.                         DoGrowWindow(window, event);
  1531.  
  1532.                     inGoAway: 
  1533.                         IF TrackGoAway(window, event.where) THEN
  1534.                             ignore := DoCloseWindow(window); { we don't care if cancelled }
  1535.  
  1536.                     inZoomIn, inZoomOut: 
  1537.  
  1538.                         IF TrackBox(window, event.where, part) THEN
  1539.                             DoZoomWindow(window, part);
  1540.                 END; { case }
  1541.             END; { mouseDown }
  1542.  
  1543.             keyDown, autoKey:  BEGIN
  1544.                 key := CHR(BAnd(event.message, charCodeMask));
  1545.                 IF BAnd(event.modifiers, cmdKey) <> 0 THEN BEGIN { Command key down }
  1546.                     IF event.what = keyDown THEN BEGIN
  1547.                         AdjustMenus; { enable/disable/check menu items properly }
  1548.                         DoMenuCommand(MenuKey(key));
  1549.                     END; { if }
  1550.                 END
  1551.                 ELSE
  1552.                     DoKeyDown(event);
  1553.             END; { keyDown }
  1554.  { call DoActivate with the window and... }
  1555.  
  1556.             activateEvt: { TRUE for activate, FALSE for deactivate }
  1557.                 DoActivate(WindowPtr(event.message), BAND(event.modifiers, activeFlag) <> 0);
  1558.  
  1559.             updateEvt: { call DoUpdate with the window to update }
  1560.                 DoUpdate(WindowPtr(event.message));
  1561.  
  1562.             diskEvt: 
  1563.                 IF HiWrd(event.message) <> noErr THEN BEGIN
  1564.                     SetPt(aPoint, kDILeft, kDITop);
  1565.                     err := DIBadMount(aPoint, event.message);
  1566.                 END;
  1567.  
  1568.             kOSEvent: 
  1569.                 CASE BAnd(BRotL(event.message, 8), $FF) OF    { high byte of message }
  1570.                     kMouseMovedMessage: 
  1571.                         DoIdle; { mouse moved is also an idle event }
  1572.  
  1573.                     kSuspendResumeMessage:  BEGIN
  1574.                         gInBackground := BAnd(event.message, kResumeMask) = 0;
  1575.                         DoActivate(FrontWindow, NOT gInBackground);
  1576.                     END; { kSuspendResumeMessage }
  1577.                 END;
  1578.         END; { case }
  1579.     END; { DoEvent }
  1580.  
  1581. {$S Main}
  1582.     PROCEDURE EventLoop;
  1583.  
  1584. {    Get events forever, and handle them by calling DoEvent.}
  1585. {     Also call AdjustCursor each time through the loop. }
  1586.  
  1587.         VAR
  1588.             cursorRgn: RgnHandle;
  1589.             gotEvent: BOOLEAN;
  1590.             event: EventRecord;
  1591.             mouse: Point;
  1592.  
  1593.     BEGIN { EventLoop }
  1594.         cursorRgn := NewRgn; { we'll pass an empty region to WNE the first time thru }
  1595.         REPEAT
  1596.             IF gHasWaitNextEvent THEN BEGIN
  1597.                 GetGlobalMouse(mouse);        {since we might go to sleep}
  1598.                 AdjustCursor(mouse, cursorRgn);
  1599.                 gotEvent := WaitNextEvent(everyEvent, event, GetSleep, cursorRgn)
  1600.             END
  1601.             ELSE BEGIN
  1602.                 SystemTask;
  1603.                 gotEvent := GetNextEvent(everyEvent, event);
  1604.             END; { if }
  1605.             IF gotEvent THEN BEGIN
  1606.                 AdjustCursor(event.where, cursorRgn);
  1607.                 DoEvent(event);
  1608.             END
  1609.             ELSE
  1610.                 DoIdle;
  1611.         UNTIL FALSE; { loop forever }
  1612.     END; { EventLoop }
  1613.  
  1614. {    This routine is automatically linked in by the MPW Linker. This external}
  1615. {    reference to it is done so that we can unload its segment, %A5Init. }
  1616.  
  1617. {$S Main}
  1618. BEGIN { main program }
  1619.     MaxApplZone;                { expand the heap so code segments load at the top }
  1620.     Initialize;                    { initialize the program }
  1621.     UnloadSeg(@Initialize);    { note that Initialize must not be in Main! }
  1622.     EventLoop;                    { call the main event loop }
  1623. END. { main program }